/**
 * \file   opcode.cpp
 * \author Fabian Jesus Machado
 * \date   Septiembre de 2011
 * 
 *  Este archivo es parte del proyecto NPASM, un ensamblador para
 * microcontroladores PIC con sintaxis Intel, desarrollado inicialmente
 * por Fabian Machado (fabianjsm@gmail.com, twitter@fabianjsm).
 *  El codigo fuente esta diponible en el repositorio SVN de Google:
 *      http://npasm.googlecode.com/svn/trunk.
 * 
 * 
 */
#include "entorno.h"
#include "opcode.h"
#include "sintaxis.h"
#include "ts.h"

opcode_t cmd_drtv[] = {
	/* Registro de trabajo */
	{"w",       W},
	
	/* Comandos */
	{"db",      CMD_DB},
	{"dw",      CMD_DW},
	{"dq",      CMD_DQ},
	{"section", CMD_SECTION},
	{"align",   CMD_ALIGN},
	{"resb",    CMD_RESB},
	{"resw",    CMD_RESW},
	{"resq",    CMD_RESQ},
	
	/* Directivas */
	{"log",     DRTV_LOG},
	{"define",  DRTV_DEFINE},
	{"include", DRTV_INCLUDE},
};

/* Por ahora solo OPCODE 14 :( */
opcode_t op14[] = {
	/* Instrucciones que no requieren argumento */
	/* Instr    Clase       OpCod */
	{"clrwdt",  INSTR_0,    0x0064},
	{"iret",    INSTR_0,    0x0009},
	{"nop",     INSTR_0,    0x0000},
	{"ret",     INSTR_0,    0x0008},
	{"sleep",   INSTR_0,    0x0063},
	
	/* Instrucciones que requieren un argumento (direccion) */
	/* Instr    Clase       OpCod */
	{"call",    INSTR_1A,   0x2000},
	{"goto",    INSTR_1A,   0x2800},
	{"jmp",     INSTR_1A,   0x2800},

	/* Instrucciones que requieren un argumento (reg gral o W)*/
	/* Instr    Clase       op0(F)   op1(W) */
	{"clr",     INSTR_1FW,  0x0180,  0x0103},
	{"com",     INSTR_1FW,  0x0980,  0x3AFF},
	{"dec",     INSTR_1FW,  0x0380,  0x3EFF},
	{"inc",     INSTR_1FW,  0x0A80,  0x3E01},
	{"rl",      INSTR_1FW,  0x0D80,  0x0000},
	{"rr",      INSTR_1FW,  0x0C80,  0x0000},
	
	/* BCF: 0x1000, BSF: 0x1400, BTFSC: 0x1800, BTFSS: 0x1C00 */
	/* Instr    Clase       Op0(F)   Op1(f.k) */
	{"clr",     INSTR_2FK,  0x0180,  0x1000},
	{"set",     INSTR_2FK,  0x0000,  0x1400},
	{"sz",      INSTR_2FK,  0x0000,  0x1800},
	{"jz",      INSTR_2FK,  0x0000,  0x1800},
	{"snz",     INSTR_2FK,  0x0000,  0x1C00},
	{"jnz",     INSTR_2FK,  0x0000,  0x1C00},
	{"ss",      INSTR_2FK,  0x0000,  0x1C00},
	{"js",      INSTR_2FK,  0x0000,  0x1C00},
	
	/* Instrucciones que requieren dos argumentos */
	/* Instr Clase          op0(F,W) op1(W,F) op2(W,K) */
	{"add",  INSTR_2FW_FKW, 0x0780,  0x0700,  0x3E00},
	{"and",  INSTR_2FW_FKW, 0x0580,  0x0500,  0x3900},
	{"mov",  INSTR_2FW_FKW, 0x0080,  0x0800,  0x3000},
	{"or",   INSTR_2FW_FKW, 0x0480,  0x0400,  0x3800},
	{"xor",  INSTR_2FW_FKW, 0x0680,  0x0600,  0x3A00},
	
	/* Instrucciones especiales */
	{"mkretlw", MKRETLW},
	
	{0}
};

void cargar_tabla(ts *tabla, opcode_t *_op)
{
	simbolo *sbl;
	opcode_t *op;
	for(op = _op; op->inst; op++) {
		sbl = tabla->Insertar(op->inst);
		sbl->SetTipo(op->clase);
		sbl->SetOp(op);
		sbl->SetUcase(true);
	}
}

/** Esta funcion es amiga de la clase \a entorno */
void opcodes()
{
	cargar_tabla(Entorno->TS, cmd_drtv);
	cargar_tabla(Entorno->TS, op14);
}
